home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / KPlib 1.2.1 / KPString.cxx < prev    next >
Encoding:
Text File  |  1994-11-07  |  12.1 KB  |  484 lines  |  [TEXT/R*ch]

  1. // A module of KPlib v1.2.1.
  2. // Written by Keith Pomakis during the summer of 1994.
  3. // Released to the public domain on October 10, 1994.
  4.  
  5. #include <iostream.h>
  6. #include <stdlib.h>
  7. #include <iomanip.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include "KPbasic.h"
  11. #include "KPString.h"
  12. #include "KPList.h"
  13.  
  14. const int KPString::max_token_size = 200;
  15. const int KPString::max_line_size = 600;
  16. KPString::Data KPString::null_data;
  17.  
  18. /****************************************************************************/
  19.  
  20. KPString::Data *
  21. KPString::new_data(int length)
  22. {
  23.     if (length > 0) {
  24.         Data *data = (Data *) malloc(sizeof(Data) + length);
  25.         check_mem(data);
  26.         data->ref_count = 0;
  27.         data->length = length;
  28.         data->chars[length] = '\0';
  29.         return data;
  30.     }
  31.     else
  32.         return &null_data;
  33. }
  34.  
  35. void
  36. KPString::replace_data(int length)
  37. {
  38.     if (length == my_data->length && my_data->ref_count <= 1)
  39.         return;
  40.  
  41.     if (my_data != &null_data && --my_data->ref_count == 0)
  42.         free(my_data);
  43.  
  44.     if (length > 0) {
  45.         my_data = (Data *) malloc(sizeof(Data) + length);
  46.         check_mem(my_data);
  47.         my_data->ref_count = 1;
  48.         my_data->length = length;
  49.         my_data->chars[length] = '\0';
  50.     }
  51.     else
  52.         my_data = &null_data;
  53. }
  54.  
  55. void
  56. KPString::replace_data(Data *data)
  57. {
  58.     if (my_data != &null_data && --my_data->ref_count == 0)
  59.         free(my_data);
  60.  
  61.     if (data != &null_data)
  62.         data->ref_count++;
  63.     my_data = data;
  64. }
  65.  
  66. void
  67. KPString::make_unique()
  68. {
  69.     if (my_data->ref_count > 1) {
  70.         Data *data = new_data(length());
  71.         ::memcpy(data->chars, chars(), length());
  72.         my_data->ref_count--;
  73.         my_data = data;
  74.         my_data->ref_count++;
  75.     }
  76. }
  77.  
  78. /****************************************************************************/
  79.  
  80. istream &
  81. operator>>(istream &stream, KPString &s)
  82. {
  83.     char buffer[KPString::max_token_size+1];
  84.  
  85.     stream >> setw(KPString::max_token_size) >> buffer;
  86.     if (stream) {
  87.         const int new_length = ::strlen(buffer);
  88.         s.replace_data(new_length);
  89.         ::memcpy(s.chars(), buffer, new_length);
  90.     }
  91.     else
  92.         s.replace_data(0);
  93.  
  94.     return stream;
  95. }
  96.  
  97. /****************************************************************************/
  98.  
  99. KPString
  100. operator+(const char *s1, const KPString &s2)
  101. {
  102.     const int s1_length = ::strlen(s1);
  103.  
  104.     if (s1_length == 0)
  105.         return s2;
  106.     else {
  107.         KPString newstring;
  108.         newstring.replace_data(s1_length + s2.length());
  109.         ::memcpy(newstring.chars(), s1, s1_length);
  110.         ::memcpy(&(newstring.chars())[s1_length], s2.chars(), s2.length());
  111.         return newstring;
  112.     }
  113. }
  114.  
  115. /****************************************************************************/
  116.  
  117. KPString
  118. KPString::operator+(const KPString &s) const
  119. {
  120.     if (length() == 0)
  121.         return s;
  122.     else if (s.length() == 0)
  123.         return *this;
  124.     else {
  125.         KPString newstring;
  126.         newstring.replace_data(length() + s.length());
  127.         ::memcpy(newstring.chars(), chars(), length());
  128.         ::memcpy(&(newstring.chars())[length()], s.chars(), s.length());
  129.         return newstring;
  130.     }
  131. }
  132.  
  133. /****************************************************************************/
  134.  
  135. KPString
  136. KPString::operator+(const char *s) const
  137. {
  138.     const int s_length = ::strlen(s);
  139.  
  140.     if (s_length == 0)
  141.         return *this;
  142.     else {
  143.         KPString newstring;
  144.         newstring.replace_data(length() + s_length);
  145.         ::memcpy(newstring.chars(), chars(), length());
  146.         ::memcpy(&(newstring.chars())[length()], s, s_length);
  147.         return newstring;
  148.     }
  149. }
  150.  
  151. /****************************************************************************/
  152.  
  153. KPString
  154. KPString::substr(int index, int len) const
  155. {
  156.     // A negative index specifies an index from the right of the string.
  157.     if (index < 0)
  158.         index += length();
  159.  
  160.     // A length of -1 specifies the rest of the string.
  161.     if (len == -1)
  162.         len = length() - index;
  163.  
  164.     if (index<0 || index>=length() || len<0 || len>length()-index)
  165.         invalid_args_error("substr()");
  166.  
  167.     KPString newstring;
  168.     newstring.replace_data(len);
  169.     ::memcpy(newstring.chars(), &chars()[index], len);
  170.  
  171.     return newstring;
  172. }
  173.  
  174. /****************************************************************************/
  175.  
  176. KPString &
  177. KPString::cut(int index, int len)
  178. {
  179.     if (len == 0)
  180.         return *this;
  181.  
  182.     // A negative index specifies an index from the right of the string.
  183.     if (index < 0)
  184.         index += length();
  185.  
  186.     // A length of -1 specifies the rest of the string.
  187.     if (len == -1)
  188.         len = length() - index;
  189.  
  190.     if (index<0 || index>=length() || len<0 || len>length()-index)
  191.         invalid_args_error("cut()");
  192.  
  193.     Data *data = new_data(length() - len);
  194.     if (index > 0)
  195.         ::memcpy(data->chars, chars(), index);
  196.     ::strcpy(&data->chars[index], &chars()[index+len]);
  197.     replace_data(data);
  198.  
  199.     return *this;
  200. }
  201.  
  202. /****************************************************************************/
  203.  
  204. KPString &
  205. KPString::replace_substr(const KPString &s, int index, int len)
  206. {
  207.     // A negative index specifies an index from the right of the string.
  208.     if (index < 0)
  209.         index += length();
  210.  
  211.     // A length of -1 specifies the rest of the string.
  212.     if (len == -1)
  213.         len = length() - index;
  214.  
  215.     if (index<0 || index>=length() || len<0 || len>length()-index)
  216.         invalid_args_error("replace_substr()");
  217.  
  218.     if (len == s.length() && my_data->ref_count == 1)
  219.         ::memcpy(&chars()[index], s.chars(), len);
  220.     else {
  221.         Data *data = new_data(length() - len + s.length());
  222.         if (index > 0)
  223.             ::memcpy(data->chars, chars(), index);
  224.         if (s.length() > 0)
  225.             ::memcpy(&data->chars[index], s.chars(), s.length());
  226.         ::strcpy(&data->chars[index+s.length()], &chars()[index+len]);
  227.         replace_data(data);
  228.     }
  229.  
  230.     return *this;
  231. }
  232.  
  233. /****************************************************************************/
  234.  
  235. KPString &
  236. KPString::replace_substr(const char *s, int index, int len)
  237. {
  238.  
  239.     // A negative index specifies an index from the right of the string.
  240.     if (index < 0)
  241.         index += length();
  242.  
  243.     // A length of -1 specifies the rest of the string.
  244.     if (len == -1)
  245.         len = length() - index;
  246.  
  247.     if (index<0 || index>=length() || len<0 || len>length()-index)
  248.         invalid_args_error("replace_substr()");
  249.  
  250.     const int s_length = ::strlen(s);
  251.  
  252.     if (len == s_length && my_data->ref_count == 1)
  253.         ::memcpy(&chars()[index], s, len);
  254.     else {
  255.         Data *data = new_data(length() - len + s_length);
  256.         if (index > 0)
  257.             ::memcpy(data->chars, chars(), index);
  258.         if (s_length > 0)
  259.             ::memcpy(&data->chars[index], s, s_length);
  260.         ::strcpy(&data->chars[index+s_length], &chars()[index+len]);
  261.         replace_data(data);
  262.     }
  263.  
  264.     return *this;
  265. }
  266.  
  267. /****************************************************************************/
  268.  
  269. KPString &
  270. KPString::insert(const KPString &s, int index)
  271. {
  272.     // A negative index specifies an index from the right of the string.
  273.     if (index < 0)
  274.         index += length();
  275.  
  276.     if (index < 0 || index >= length())
  277.         invalid_index_error("insert()");
  278.  
  279.     if (s.length() > 0) {
  280.         Data *data = new_data(length() + s.length());
  281.         if (index > 0)
  282.             ::memcpy(data->chars, chars(), index);
  283.         ::memcpy(&data->chars[index], s.chars(), s.length());
  284.         ::strcpy(&data->chars[index+s.length()], &chars()[index]);
  285.         replace_data(data);
  286.     }
  287.  
  288.     return *this;
  289. }
  290.  
  291. /****************************************************************************/
  292.  
  293. KPString &
  294. KPString::insert(const char *s, int index)
  295. {
  296.     // A negative index specifies an index from the right of the string.
  297.     if (index < 0)
  298.         index += length();
  299.  
  300.     if (index < 0 || index >= length())
  301.         invalid_index_error("insert()");
  302.  
  303.     const int s_length = ::strlen(s);
  304.  
  305.     if (s_length > 0) {
  306.         Data *data = new_data(length() + s_length);
  307.         if (index > 0)
  308.             ::memcpy(data->chars, chars(), index);
  309.         ::memcpy(&data->chars[index], s, s_length);
  310.         ::strcpy(&data->chars[index+s_length], &chars()[index]);
  311.         replace_data(data);
  312.     }
  313.  
  314.     return *this;
  315. }
  316.  
  317. /****************************************************************************/
  318.  
  319. KPString &
  320. KPString::to_upper()
  321. {
  322.     make_unique();
  323.  
  324.     for (char *p = chars(); *p; p++)
  325.         if (islower(*p))
  326.             *p = toupper(*p);
  327.  
  328.     return *this;
  329. }
  330.  
  331. /****************************************************************************/
  332.  
  333. KPString &
  334. KPString::to_lower()
  335. {
  336.     make_unique();
  337.  
  338.     for (char *p = chars(); *p; p++)
  339.         if (isupper(*p))
  340.             *p = tolower(*p);
  341.  
  342.     return *this;
  343. }
  344.  
  345. /****************************************************************************/
  346.  
  347. int
  348. KPString::index_of(const char *s, int start_index) const
  349. {
  350.     // A negative index specifies an index from the right of the string.
  351.     if (start_index < 0)
  352.         start_index += length();
  353.  
  354.     if (start_index < 0 || start_index >= length())
  355.         invalid_index_error("index_of()");
  356.  
  357.     const char *index;
  358.     if (!(index = strstr(&chars()[start_index], s)))
  359.         return -1;
  360.     else
  361.         return index - chars();
  362. }
  363.  
  364. /****************************************************************************/
  365.  
  366. int
  367. KPString::index_of(char c, int start_index) const
  368. {
  369.     // A negative index specifies an index from the right of the string.
  370.     if (start_index < 0)
  371.         start_index += length();
  372.  
  373.     if (start_index < 0 || start_index >= length())
  374.         invalid_index_error("index_of()");
  375.  
  376.     const char *index;
  377.  
  378.     if (c == '\0')
  379.         return -1;
  380.  
  381.     else if (!(index = (char *) ::memchr(&chars()[start_index], c,
  382.                                          length()-start_index)))
  383.         return -1;
  384.     else
  385.         return index - chars();
  386. }
  387.  
  388. /****************************************************************************/
  389.  
  390. KPList<KPString>
  391. KPString::tokens(const char *separators) const
  392. {
  393.     KPList<KPString> list;
  394.     int token_length, index = 0;
  395.  
  396.     do {
  397.         index += ::strspn(&chars()[index], separators);
  398.         token_length = ::strcspn(&chars()[index], separators);
  399.         if (token_length > 0)
  400.             list.add_to_tail(substr(index, token_length));
  401.         index += token_length;
  402.     } while (token_length > 0);
  403.  
  404.     return list;
  405. }
  406.  
  407. /****************************************************************************/
  408.  
  409. KPList<KPString> KPString::tokens(char separator) const
  410. {
  411.     char separators[2];
  412.     separators[0] = separator;
  413.     separators[1] = '\0';
  414.     return tokens(separators);
  415. }
  416.  
  417. /****************************************************************************/
  418.  
  419. KPString &
  420. KPString::read_line(istream &stream)
  421. {
  422.     char buffer[max_line_size+1];
  423.     stream.getline(buffer, max_line_size);
  424.     const int new_length = ::strlen(buffer);
  425.     Data *data = new_data(new_length);
  426.     ::memcpy(data->chars, buffer, new_length);
  427.     replace_data(data);
  428.  
  429.     return *this;
  430. }
  431.  
  432. /****************************************************************************/
  433.  
  434. KPString &
  435. KPString::read_token(istream &stream, const char *separators)
  436. {
  437.     int c;
  438.     const int num_of_separators = ::strlen(separators);
  439.  
  440.     // Scan for the first character of the token.
  441.     do {
  442.         c = stream.get();
  443.         if (c == EOF) {
  444.             replace_data(0);
  445.             return *this;
  446.         }
  447.     } while (::memchr(separators, c, num_of_separators));
  448.  
  449.     int i = 0;
  450.     char buffer[max_token_size];
  451.  
  452.     // Read in the token.
  453.     do {
  454.         buffer[i++] = c;
  455.         c = stream.get();
  456.     } while (c != EOF && !::memchr(separators, c, num_of_separators));
  457.  
  458.     stream.putback(c);
  459.     replace_data(i);
  460.     ::memcpy(chars(), buffer, i);
  461.  
  462.     return *this;
  463. }
  464.  
  465. /****************************************************************************/
  466.  
  467. void
  468. KPString::invalid_args_error(const char *fname)
  469. {
  470.     cerr << "KPString::" << fname << " - invalid arguments\n";
  471.     exit(EXIT_FAILURE);
  472. }
  473.  
  474. /****************************************************************************/
  475.  
  476. void
  477. KPString::invalid_index_error(const char *fname)
  478. {
  479.     cerr << "KPString::" << fname << " - invalid index\n";
  480.     exit(EXIT_FAILURE);
  481. }
  482.  
  483. /****************************************************************************/
  484.